package com.pf.log.utils;

import com.google.common.collect.Lists;
import com.pf.common.enums.BaseResultEnum;
import com.pf.common.exception.BusinessException;
import com.pf.common.utils.CustomBeanUtils;
import com.pf.common.utils.CustomStringUtils;
import com.pf.common.utils.JacksonUtils;
import com.pf.log.annotation.LogBusinessId;
import com.pf.log.annotation.LogDateTimeFormat;
import com.pf.log.annotation.LogField;
import com.pf.log.annotation.converter.Converter;
import com.pf.log.annotation.converter.DefaultConverter;
import com.pf.log.enums.LogOperationTypeEnum;
import com.pf.log.param.*;
import com.pf.rule.mapper.entity.LogEntity;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.Collator;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author PanFei
 * @version 1.0.0
 * @createTime 2023/6/2 21:43
 */
@Slf4j
public class LogUtils {

    /**
     * 获取新增操作历史记录
     *
     * @param obj            数据对象
     * @param dataDictMap    数据字典
     * @param extendLogParam 扩展日志参数
     * @param <T>
     * @return 操作日志信息
     * @throws Exception
     */
    public static <T> LogEntity getAddOperationLog(T obj, Map<String, Map<String, String>> dataDictMap, LogExtendLogParam extendLogParam) throws Exception {
        extendLogParam = extendLogParam != null ? extendLogParam : new LogExtendLogParam();
        Class<?> clazz = obj.getClass();
        // 1.获取含有 @LogField 和 @LogBusinessId 注解的字段信息
        Map<Class<? extends Annotation>, List<Field>> annotationFieldMap = CustomBeanUtils.getRecursiveFieldsByUpward(clazz, Lists.newArrayList(LogField.class, LogBusinessId.class));
        // 2.校验 @LogBusinessId 注解并获取 LogBusinessId 相关信息
        LogBusinessIdParam logBusinessIdParam = checkLogBusinessIdAndGet(obj, annotationFieldMap, extendLogParam);
        if (StringUtils.isBlank(logBusinessIdParam.getLogBusinessIdValue())) {
            log.error(">>>>> getAddOperationLog：目标对象类型[{}]@LogBusinessId标识的字段值为空......", clazz.getName());
            return null;
        }
        // 3.校验实体 @LogField 注解，并获取含有moduleCode的@LogField 注解的字段
        List<Field> logFieldList = checkLogFieldAndGetFields(clazz, logBusinessIdParam, annotationFieldMap, extendLogParam);
        List<LogOperationFieldParam> logOperationFieldList = Lists.newArrayList();
        // 4.循环获取每个含有 @LogField 注解字段的操作字段信息
        for (Field field : logFieldList) {
            getLogOperationFieldsForAdd(obj, field, dataDictMap, logOperationFieldList);
        }
        // 5.判断是否有扩展字段，如果有则追加扩展字段的历史记录信息
        if (Boolean.TRUE.equals(extendLogParam.getIsContainsExtendField())) {
            parseExtendFieldForAddOperationLog(logBusinessIdParam, extendLogParam, logOperationFieldList);
        }
        String operationType = StringUtils.isNotBlank(extendLogParam.getOperationType()) ? LogOperationTypeEnum.ADD.getCode() + "（" + extendLogParam.getOperationType() + "）" : LogOperationTypeEnum.ADD.getCode();
        // 6.返回历史记录
        return buildLogEntity(operationType, logBusinessIdParam, logOperationFieldList);
    }

    /**
     * 获取编辑操作日志信息
     *
     * @param oldObj         修改前数据对象
     * @param newObj         修改后数据对象
     * @param dataDictMap    数据字典
     * @param extendLogParam 日志扩展参数
     * @param <T>
     * @return 操作日志信息
     * @throws Exception
     */
    public static <T> LogEntity getModifyOperationLog(T oldObj, T newObj, Map<String, Map<String, String>> dataDictMap, LogExtendLogParam extendLogParam) throws Exception {
        extendLogParam = extendLogParam != null ? extendLogParam : new LogExtendLogParam();
        Class<?> clazz = newObj.getClass();
        // 1.获取含有 @LogField 和 @LogBusinessId 注解的字段信息
        Map<Class<? extends Annotation>, List<Field>> annotationFieldMap = CustomBeanUtils.getRecursiveFieldsByUpward(clazz, Lists.newArrayList(LogField.class, LogBusinessId.class));
        // 2.校验 @LogBusinessId 注解并获取 LogBusinessId 相关信息
        LogBusinessIdParam logBusinessIdParam = checkLogBusinessIdAndGet(newObj, annotationFieldMap, extendLogParam);
        if (StringUtils.isBlank(logBusinessIdParam.getLogBusinessIdValue())) {
            log.error(">>>>> getModifyOperationLog：目标对象类型[{}]@LogBusinessId标识的字段值为空...", clazz.getSimpleName());
            return null;
        }
        // 3.校验实体 @LogField 注解，并获取含有moduleCode的@LogField 注解的字段
        List<Field> logFieldList = checkLogFieldAndGetFields(clazz, logBusinessIdParam, annotationFieldMap, extendLogParam);
        List<LogOperationFieldParam> logOperationFieldList = Lists.newArrayList();
        // 4.循环获取每个含有 @LogField 注解字段的操作字段信息
        for (Field field : logFieldList) {
            getLogOperationFieldsForModify(oldObj, newObj, field, dataDictMap, logOperationFieldList);
        }
        // 5.判断是否有扩展字段，如果有则追加扩展字段的历史记录信息
        if (Boolean.TRUE.equals(extendLogParam.getIsContainsExtendField())) {
            parseExtendFieldForModifyOperationLog(logBusinessIdParam, extendLogParam, logOperationFieldList);
        }
        // 6.返回历史记录
        String operationType = StringUtils.isNotBlank(extendLogParam.getOperationType()) ? LogOperationTypeEnum.UPDATE.getCode() + "（" + extendLogParam.getOperationType() + "）" : LogOperationTypeEnum.UPDATE.getCode();
        return buildLogEntity(operationType, logBusinessIdParam, logOperationFieldList);
    }

    /**
     * 获取删除/恢复操作日志信息
     *
     * @param obj            目标对象
     * @param isDeleted      true-删除  false-恢复
     * @param extendLogParam 日志扩展参数
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> LogEntity getDeleteOrRecoverOperationLog(T obj, boolean isDeleted, LogExtendLogParam extendLogParam) throws Exception {
        extendLogParam = extendLogParam != null ? extendLogParam : new LogExtendLogParam();
        Class<?> clazz = obj.getClass();
        // 1.获取含有@LogBusinessId注解的字段集合
        Map<Class<? extends Annotation>, List<Field>> annotationFieldMap = CustomBeanUtils.getRecursiveFieldsByUpward(clazz, Lists.newArrayList(LogBusinessId.class));
        // 2.校验实体对象@LogBusinessId注解并获取值
        LogBusinessIdParam logBusinessIdParam = checkLogBusinessIdAndGet(obj, annotationFieldMap, extendLogParam);
        if (StringUtils.isBlank(logBusinessIdParam.getLogBusinessIdValue())) {
            log.error(">>>>> getDeleteOrRecoverOperationLog：类型{}用@LogBusinessId标识的字段值为空...", clazz.getName());
            return null;
        }
        // 3.获取历史记录
        return getLogOperationForDeleteOrRecover(logBusinessIdParam, isDeleted, extendLogParam);
    }

    /**
     * 获取删除/恢复操作历史记录
     *
     * @param clazz          目标对象类型
     * @param businessId     业务数据id
     * @param isDeleted      true-删除 false-恢复
     * @param extendLogParam 日志扩展参数
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> LogEntity getDeleteOrRecoverOperationLog(Class<T> clazz, String businessId, boolean isDeleted, LogExtendLogParam extendLogParam) throws Exception {
        extendLogParam = extendLogParam != null ? extendLogParam : new LogExtendLogParam();
        // 1.获取含有@LogBusinessId注解的字段集合
        Map<Class<? extends Annotation>, List<Field>> annotationFieldMap = CustomBeanUtils.getRecursiveFieldsByUpward(clazz, Lists.newArrayList(LogBusinessId.class));
        // 2.校验实体 @LogBusinessId 注解
        Field logBusinessIdField = checkLogBusinessId(clazz, annotationFieldMap);
        // 3.获取 LogBusinessId 相关信息，并组装返回 LogBusinessIdParam
        LogBusinessId logBusinessId = logBusinessIdField.getAnnotation(LogBusinessId.class);
        String fieldName = StringUtils.isNotBlank(logBusinessId.alias()) ? logBusinessId.alias() : logBusinessIdField.getName();
        String moduleCode = StringUtils.isNotBlank(extendLogParam.getModuleCode()) ? extendLogParam.getModuleCode() : logBusinessId.moduleCode();
        LogBusinessIdParam logBusinessIdParam = new LogBusinessIdParam(fieldName, moduleCode, businessId);
        // 4.获取历史记录
        return getLogOperationForDeleteOrRecover(logBusinessIdParam, isDeleted, extendLogParam);
    }

    /**
     * 新建操作里是记录解析扩展字段信息
     *
     * @param logBusinessIdParam
     * @param extendLogParam
     * @param logOperationFieldList
     */
    private static void parseExtendFieldForAddOperationLog(LogBusinessIdParam logBusinessIdParam, LogExtendLogParam
            extendLogParam, List<LogOperationFieldParam> logOperationFieldList) {
        String businessId = logBusinessIdParam.getLogBusinessIdValue();
        List<BusinessExtendLogFieldParam> businessExtendLogFieldList = extendLogParam.getBusinessExtendLogFieldList();
        if (CollectionUtils.isEmpty(businessExtendLogFieldList)) {
            log.error(">>>>> parseExtendFieldForAddOperationLog：未配置业务扩展字段信息...");
            return;
        }
        Map<String, BusinessExtendLogFieldParam> businessExtendLogFieldMap = businessExtendLogFieldList.stream().collect(Collectors.toMap(BusinessExtendLogFieldParam::getBusinessId, Function.identity(), (key1, key2) -> key2));
        BusinessExtendLogFieldParam businessExtendLogFieldParam = businessExtendLogFieldMap.get(businessId);
        if (businessExtendLogFieldParam == null || CollectionUtils.isEmpty(businessExtendLogFieldParam.getNewExtendFieldList())) {
            log.error(">>>>> parseExtendFieldForAddOperationLog：业务id{}未配置扩展字段信息...");
            return;
        }
        // 循环处理扩展字段
        List<LogExtendFieldParam> newExtendFieldList = businessExtendLogFieldParam.getNewExtendFieldList();
        for (LogExtendFieldParam logExtendField : newExtendFieldList) {
            String fieldValue = StringUtils.defaultString(convertExtendFieldValue(logExtendField));
            if (StringUtils.isAnyBlank(logExtendField.getFieldDescName(), fieldValue)) {
                log.error(">>>>> parseExtendField：请求参数 logExtendField中的 fieldDescName或fieldValue字段值为空...");
                continue;
            }
            logOperationFieldList.add(new LogOperationFieldParam(logExtendField.getFieldDescName(), "", fieldValue));
        }
    }

    /**
     * 获取新增操作的操作日志信息
     *
     * @param obj                数据对象
     * @param field              用@LogField标识的字段
     * @param dataDictMap        数据字典
     * @param logOperationFields 目标结果集
     * @param <T>
     * @throws Exception
     */
    private static <T> void getLogOperationFieldsForAdd(T obj, Field field, Map<String, Map<String, String>> dataDictMap,
                                                        List<LogOperationFieldParam> logOperationFields) throws Exception {
        // 1.获取field字段值以及字段名称
        field.setAccessible(true);
        Object value = field.get(obj);
        LogField logField = field.getAnnotation(LogField.class);
        String fieldName = StringUtils.isNotBlank(logField.alias()) ? logField.alias() : field.getName();
        // 2.转换字段值
        String logFieldValue;
        if (field.isAnnotationPresent(LogDateTimeFormat.class)) {
            // 获取日期字段值
            LogDateTimeFormat logDateTimeFormat = field.getAnnotation(LogDateTimeFormat.class);
            SimpleDateFormat sdf = new SimpleDateFormat(logDateTimeFormat.pattern());
            logFieldValue = value != null ? sdf.format(value) : null;
        } else {
            logFieldValue = CustomStringUtils.object2Str(value);
            Class<? extends Converter> converterClass = logField.converter();
            if (!DefaultConverter.class.equals(converterClass)) {
                String converterKey = logField.converterKey();
                if (StringUtils.isBlank(converterKey)) {
                    Converter converter = converterClass.newInstance();
                    logFieldValue = converter.getDescription(logFieldValue);
                } else {
                    Constructor<? extends Converter> constructor = converterClass.getConstructor(String.class, Map.class);
                    Converter converter = constructor.newInstance(converterKey, dataDictMap);
                    logFieldValue = converter.getDescription(logFieldValue);
                }
            }
        }
        if (StringUtils.isNotBlank(logFieldValue)) {
            logFieldValue = StringUtils.defaultString(logFieldValue);
            logOperationFields.add(new LogOperationFieldParam(fieldName, "", logFieldValue));
        }
    }

    /**
     * 转换TEXT/DATE/NUMBER扩展字段值
     *
     * @param logExtendFieldParam
     * @return
     */
    private static String convertExtendFieldValue(LogExtendFieldParam logExtendFieldParam) {
        if (logExtendFieldParam.getFieldValue() == null) {
            return null;
        }
        String fieldValue = null;
        try {
            switch (logExtendFieldParam.getFieldType()) {
                case TEXT:
                    fieldValue = CustomStringUtils.object2Str(logExtendFieldParam.getFieldValue());
                    break;
                case DATE:
                    String dateFormatPattern = StringUtils.isNotBlank(logExtendFieldParam.getFormatPattern()) ? logExtendFieldParam.getFormatPattern() : "yyyy-MM-dd";
                    SimpleDateFormat sdf = new SimpleDateFormat(dateFormatPattern);
                    fieldValue = sdf.format(logExtendFieldParam.getFieldValue());
                    break;
                case NUMBER:
                    String numberFormatPattern = StringUtils.isNotBlank(logExtendFieldParam.getFormatPattern()) ? logExtendFieldParam.getFormatPattern() : "#";
                    DecimalFormat decimalFormat = new DecimalFormat(numberFormatPattern);
                    fieldValue = decimalFormat.format(new BigDecimal(logExtendFieldParam.getFieldValue().toString()));
                default:
                    log.error(">>>>> convertExtendFieldValue： logExtendFieldParam对象 fieldType字段值不合规...fieldType={}", logExtendFieldParam.getFieldType());
            }
        } catch (Exception e) {
            log.error(">>>>> convertExtendFieldValue：logExtendFieldParam对象fieldValue属性值转换失败... fieldValue={}", logExtendFieldParam.getFieldValue(), e);
        }
        return fieldValue;
    }

    /**
     * 编辑操作里是记录解析扩展字段信息
     *
     * @param logBusinessIdParam
     * @param extendLogParam
     * @param logOperationFieldList
     */
    private static void parseExtendFieldForModifyOperationLog(LogBusinessIdParam
                                                                      logBusinessIdParam, LogExtendLogParam extendLogParam, List<LogOperationFieldParam> logOperationFieldList) {
        String businessId = logBusinessIdParam.getLogBusinessIdValue();
        List<BusinessExtendLogFieldParam> businessExtendLogFieldList = extendLogParam.getBusinessExtendLogFieldList();
        if (CollectionUtils.isEmpty(businessExtendLogFieldList)) {
            log.error(">>>>> parseExtendFieldForModifyOperationLog：未配置扩展字段信息...");
            return;
        }
        Map<String, BusinessExtendLogFieldParam> businessExtendLogFieldMap = businessExtendLogFieldList.stream().collect(Collectors.toMap(BusinessExtendLogFieldParam::getBusinessId, Function.identity(), (key1, key2) -> key2));
        BusinessExtendLogFieldParam businessExtendLogFieldParam = businessExtendLogFieldMap.get(businessId);
        if (businessExtendLogFieldParam == null) {
            log.error(">>>>> parseExtendFieldForModifyOperationLog：业务id{}未配置扩展字段信息...", businessId);
            return;
        }
        List<LogExtendFieldParam> oldExtendFieldList = businessExtendLogFieldParam.getOldExtendFieldList();
        List<LogExtendFieldParam> newExtendFieldList = businessExtendLogFieldParam.getNewExtendFieldList();
        if (CollectionUtils.isEmpty(oldExtendFieldList) || CollectionUtils.isEmpty(newExtendFieldList) || oldExtendFieldList.size() != newExtendFieldList.size()) {
            log.error(">>>>> parseExtendFieldForModifyOperationLog：extendLogParam对象请求参数oldExtendFieldList和newExtendFieldList参数数量不一致...");
            return;
        }
        Map<String, LogExtendFieldParam> newExtendFieldMap = newExtendFieldList.stream().collect(Collectors.toMap(LogExtendFieldParam::getFieldName, Function.identity(), (key1, key2) -> key2));
        String oldFieldValue;
        String newFieldValue;
        for (LogExtendFieldParam oldExtendFieldParam : oldExtendFieldList) {
            oldFieldValue = StringUtils.defaultString(convertExtendFieldValue(oldExtendFieldParam));
            newFieldValue = StringUtils.defaultString(convertExtendFieldValue(newExtendFieldMap.get(oldExtendFieldParam.getFieldName())));
            if (oldFieldValue.equals(newFieldValue)) {
                continue;
            }
            logOperationFieldList.add(new LogOperationFieldParam(oldExtendFieldParam.getFieldDescName(), oldFieldValue, newFieldValue));
        }
    }

    /**
     * 获取编辑的操作日志信息
     *
     * @param oldObj             变更前数据
     * @param newObj             变更后数据
     * @param field              用@LogField标识的字段
     * @param dataDictMap        数据字典
     * @param logOperationFields 目标结果集
     * @param <T>
     * @throws Exception
     */
    private static <T> void getLogOperationFieldsForModify(T oldObj, T newObj, Field field, Map<String, Map<String, String>> dataDictMap,
                                                           List<LogOperationFieldParam> logOperationFields) throws Exception {
        field.setAccessible(true);
        Object oldValue = field.get(oldObj);
        Object newValue = field.get(newObj);
        LogField logField = field.getAnnotation(LogField.class);
        // 获取字段名称
        String fieldName = StringUtils.isNotBlank(logField.alias()) ? logField.alias() : field.getName();
        String oldLogFieldValue;
        String newLogFieldValue;
        if (field.isAnnotationPresent(LogDateTimeFormat.class)) {
            // 获取日期字段值
            LogDateTimeFormat logDateTimeFormat = field.getAnnotation(LogDateTimeFormat.class);
            SimpleDateFormat sdf = new SimpleDateFormat(logDateTimeFormat.pattern());
            oldLogFieldValue = oldValue != null ? sdf.format(oldValue) : null;
            newLogFieldValue = newValue != null ? sdf.format(newValue) : null;
        } else {
            oldLogFieldValue = CustomStringUtils.object2Str(oldValue);
            newLogFieldValue = CustomStringUtils.object2Str(newValue);
            Class<? extends Converter> converterClass = logField.converter();
            if (!DefaultConverter.class.equals(converterClass)) {
                String converterKey = logField.converterKey();
                if (StringUtils.isBlank(converterKey)) {
                    Converter converter = converterClass.newInstance();
                    oldLogFieldValue = converter.getDescription(oldLogFieldValue);
                    newLogFieldValue = converter.getDescription(newLogFieldValue);
                } else {
                    Constructor<? extends Converter> constructor = converterClass.getConstructor(String.class, Map.class);
                    Converter converter = constructor.newInstance(converterKey, dataDictMap);
                    oldLogFieldValue = converter.getDescription(oldLogFieldValue);
                    newLogFieldValue = converter.getDescription(newLogFieldValue);
                }
            }
        }
        oldLogFieldValue = StringUtils.defaultString(oldLogFieldValue);
        newLogFieldValue = StringUtils.defaultString(newLogFieldValue);
        // 判断字段 @LogField 注解是否配置了 splitRegx 属性
        String splitRegx = logField.splitRegx();
        if (StringUtils.isNotBlank(splitRegx)) {
            oldLogFieldValue = CustomStringUtils.str2DeduplicationList(oldLogFieldValue, splitRegx)
                    .stream().sorted(Comparator.comparing(Function.identity(), Collator.getInstance(Locale.CHINA)))
                    .collect(Collectors.joining(splitRegx));
            newLogFieldValue = CustomStringUtils.str2DeduplicationList(newLogFieldValue, splitRegx)
                    .stream().sorted(Comparator.comparing(Function.identity(), Collator.getInstance(Locale.CHINA)))
                    .collect(Collectors.joining(splitRegx));
        }
        if (!oldLogFieldValue.equals(newLogFieldValue)) {
            logOperationFields.add(new LogOperationFieldParam(fieldName, oldLogFieldValue, newLogFieldValue));
        }
    }

    /**
     * 校验 clazz 类型是否有 @LogField 标识的字段，并返回对应字段
     *
     * @param clazz              目标对象类型
     * @param logBusinessIdParam logBusinessId相关信息
     * @param annotationFieldMap 注解对应字段集合
     * @param extendLogParam     日志扩展信息
     * @param <T>
     */
    private static <T> List<Field> checkLogFieldAndGetFields(Class<T> clazz, LogBusinessIdParam logBusinessIdParam,
                                                             Map<Class<? extends Annotation>, List<Field>> annotationFieldMap, LogExtendLogParam extendLogParam) {
        // 1.获取含有 @LogField 标识的字段集合
        List<Field> logFieldList = annotationFieldMap.get(LogField.class);
        if (CollectionUtils.isEmpty(logFieldList)) {
            log.error(">>>>> checkLogFieldAndGetFields：实体类{}未配置@LogField标识的字段信息", clazz.getSimpleName());
            throw new BusinessException(BaseResultEnum.CONFIG_ERROR.getCode(), "实体类[" + clazz.getSimpleName() + "]未配置@LogField标识的字段信息...");
        }

        // 2.筛选出 moduleCode对应的字段信息
        logFieldList = logFieldList.stream().filter(field -> {
            LogField logField = field.getAnnotation(LogField.class);
            if (logField.moduleCodeGroup() != null && logField.moduleCodeGroup().length > 0) {
                return Lists.newArrayList(logField.moduleCodeGroup()).contains(logBusinessIdParam.getModuleCode());
            } else {
                return true;
            }
        }).collect(Collectors.toList());
        return logFieldList;
    }

    /**
     * 组装操作历史记录信息
     *
     * @param operationType         操作类型
     * @param logBusinessIdParam    logBusinessId相关信息
     * @param logOperationFieldList 操作内容
     * @return
     */
    private static LogEntity buildLogEntity(String operationType, LogBusinessIdParam logBusinessIdParam, List<LogOperationFieldParam> logOperationFieldList) {
        if (CollectionUtils.isEmpty(logOperationFieldList)) {
            return null;
        }
        return LogEntity.builder()
                .businessId(logBusinessIdParam.getLogBusinessIdValue())
                .moduleCode(logBusinessIdParam.getModuleCode())
                .operationType(operationType)
                .operationContent(JacksonUtils.toJsonString(logOperationFieldList))
                .createdBy("system")
                .build();
    }

    /**
     * 获取删除/恢复的历史记录
     *
     * @param logBusinessIdParam logBusinessId相关信息
     * @param isDeleted          true-删除 false-恢复
     * @param extendLogParam     日志扩展参数
     * @return
     */
    private static LogEntity getLogOperationForDeleteOrRecover(LogBusinessIdParam logBusinessIdParam, boolean isDeleted, LogExtendLogParam extendLogParam) {
        String oldBusinessId = null;
        String newBusinessId = null;
        String operationType;
        if (isDeleted) {
            oldBusinessId = logBusinessIdParam.getLogBusinessIdValue();
            operationType = StringUtils.isNotBlank(extendLogParam.getOperationType()) ? LogOperationTypeEnum.DELETE.getCode() + "（" + extendLogParam.getOperationType() + "）" : LogOperationTypeEnum.DELETE.getCode();
        } else {
            newBusinessId = logBusinessIdParam.getLogBusinessIdValue();
            operationType = StringUtils.isNotBlank(extendLogParam.getOperationType()) ? LogOperationTypeEnum.RECOVER.getCode() + "（" + extendLogParam.getOperationType() + "）" : LogOperationTypeEnum.RECOVER.getCode();
        }
        LogOperationFieldParam logOperationFieldParam = new LogOperationFieldParam(logBusinessIdParam.getLogBusinessIdName(), oldBusinessId, newBusinessId);
        List<LogOperationFieldParam> logOperationFieldList = Lists.newArrayList(logOperationFieldParam);
        return buildLogEntity(operationType, logBusinessIdParam, logOperationFieldList);
    }

    /**
     * 校验 @LogBusinessId 注解并获取 LogBusinessId 相关信息
     *
     * @param obj                目标对象
     * @param annotationFieldMap 含有某注解的字段集合
     * @param extendLogParam     日志扩展字段
     * @param <T>
     * @return
     * @throws Exception
     */
    private static <T> LogBusinessIdParam checkLogBusinessIdAndGet(T obj, Map<Class<? extends Annotation>, List<Field>> annotationFieldMap, LogExtendLogParam extendLogParam) throws Exception {
        // 1.校验目标对象类型 clazz 是否有且仅有一个 @LogBusinessId 标识的字段
        Class<?> clazz = obj.getClass();
        Field logBusinessIdField = checkLogBusinessId(clazz, annotationFieldMap);
        // 2.获取含有 @LogBusinessId 注解对应字段的值
        logBusinessIdField.setAccessible(true);
        String businessIdValue = StringUtils.defaultString(CustomStringUtils.object2Str(logBusinessIdField.get(obj)));
        // 3.组装 @LogBusinessId 注解相关 moduleCode，fieldName，fieldValue字段值，并组装对象 LogBusinessIdParam
        LogBusinessId logBusinessId = logBusinessIdField.getAnnotation(LogBusinessId.class);
        String moduleCode = StringUtils.isNotBlank(extendLogParam.getModuleCode()) ? extendLogParam.getModuleCode() : logBusinessId.moduleCode();
        String fieldName = StringUtils.isNotBlank(logBusinessId.alias()) ? logBusinessId.alias() : logBusinessIdField.getName();
        return new LogBusinessIdParam(fieldName, moduleCode, businessIdValue);
    }

    /**
     * 校验目标对象类型 clazz 是否有且仅有一个 @LogBusinessId 标识的字段
     *
     * @param clazz              目标对象类型
     * @param annotationFieldMap 注解字段集合
     * @param <T>
     */
    private static <T> Field checkLogBusinessId(Class<T> clazz, Map<Class<? extends Annotation>, List<Field>> annotationFieldMap) {
        List<Field> logBusinessIdFieldList = annotationFieldMap.get(LogBusinessId.class);
        if (CollectionUtils.isEmpty(logBusinessIdFieldList)) {
            log.error(">>>>> checkLogBusinessId：实体类{}未配置@LogBusinessId标识的字段", clazz.getSimpleName());
            throw new BusinessException(BaseResultEnum.CONFIG_ERROR.getCode(), "实体类[" + clazz.getSimpleName() + "]未配置@LogBusinessId标识的字段...");
        }
        if (logBusinessIdFieldList.size() != 1) {
            log.error(">>>>> checkLogBusinessId：实体类{}只能配置一个@LogBusinessId标识的字段", clazz.getSimpleName());
            throw new BusinessException(BaseResultEnum.CONFIG_ERROR.getCode(), "实体类[" + clazz.getSimpleName() + "]只能配置一个@LogBusinessId标识的字段...");
        }
        return logBusinessIdFieldList.get(0);
    }
}
